/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/
#include <StdAfx.h>
#include "mstore/O_IProp.h"
#include <otlkcon_gui.h>
#include "resource.h"
#include <commctrl.h>

otlkcon_config::otlkcon_config()
{
    clear();
}

otlkcon_config::otlkcon_config(HWND ui, otlkcon_memory *m )
{
    clear();
    memObj = m;

    ulUIParam = ui;
}

STDMETHODIMP otlkcon_config::clear()
{
    HRESULT result = S_OK;

    ulUIParam  = 0;
    isDirty    = FALSE;

    dbFilename = L"";
    xpEnabled  = FALSE;
    abEnabled  = FALSE;

    debugFileEnabled = FALSE;
    debugSMEnabled   = FALSE;
    debugDBEnabled   = FALSE;
    debugLogFilename = L"";
    debugLevel  = -1;
            
    lastAccountComboIndex = 0;

    accTypeList.insert(  pair<int,wstring>(OTLKCON_ACCOUNT_TYPE_UNDEFINED, wstring(OTLKCON_ACCOUNT_TYPE_DESC_UNDEFINED) ) );
#ifdef OTLKCON_XP_CALDAV
    accTypeList.insert(  pair<int,wstring>(OTLKCON_ACCOUNT_TYPE_CALDAV, wstring(OTLKCON_ACCOUNT_TYPE_DESC_CALDAV) ) ); 
#endif // OTLKCON_XP_CALDAV
#ifdef OTLKCON_XP_FILE
    accTypeList.insert(  pair<int,wstring>(OTLKCON_ACCOUNT_TYPE_FILE, wstring(OTLKCON_ACCOUNT_TYPE_DESC_FILE) ) ); 
#endif // OTLKCON_XP_FILE

    return result;
}

STDMETHODIMP otlkcon_config::writeRegistry()
{
    HRESULT result = S_OK;
        wchar_t szBuf[OTLKCON_REG_VALUE_MAX_LEN+1] = {0};
	DWORD szBufSize = OTLKCON_REG_VALUE_MAX_LEN;
    DWORD dwBuf = 0;
	DWORD readRetVal = 0;
    HKEY hk;

    // Get registry settings 
    result = RegCreateKeyExW(HKEY_CURRENT_USER, OTLKCON_REG_KEY,
		            0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE|KEY_READ, NULL, &hk, NULL);
    if( hk != 0 )
    {
        dwBuf  = debugLevel;
        szBufSize = 4;
        result = RegSetValueExW(hk, L"debugLevel", 0, REG_DWORD, (BYTE *)&dwBuf, szBufSize);

        dwBuf  = debugSMEnabled;
        szBufSize = 4;
        result = RegSetValueExW(hk, L"logToSMEnabled", 0, REG_DWORD, (BYTE *)&dwBuf, szBufSize);

        dwBuf  = debugDBEnabled;
        szBufSize = 4;
        result = RegSetValueExW(hk, L"logToMSVCEnabled", 0, REG_DWORD, (BYTE *)&dwBuf, szBufSize);

        dwBuf  = debugFileEnabled;
        szBufSize = 4;
        result = RegSetValueExW(hk, L"logToFileEnabled", 0, REG_DWORD, (BYTE *)&dwBuf, szBufSize);

        wcsncpy_s( szBuf, OTLKCON_REG_VALUE_MAX_LEN+1,
                        debugLogFilename.c_str(), OTLKCON_REG_VALUE_MAX_LEN);
        szBufSize = (ULONG)(wcslen( szBuf )+1)*sizeof(wchar_t);
        result = RegSetValueExW(hk, L"logFile", 0, REG_SZ, (BYTE *)szBuf, szBufSize);
    }

    return result;
}

STDMETHODIMP otlkcon_config::readRegistry()
{
    HRESULT result = S_OK;
    wchar_t szBuf[OTLKCON_REG_VALUE_MAX_LEN+1] = {0};
	DWORD szBufSize = OTLKCON_REG_VALUE_MAX_LEN;
    DWORD dwBuf = 0;
	DWORD readRetVal = 0;
    HKEY hk;

    // Get registry settings 
    result = RegCreateKeyExW(HKEY_CURRENT_USER, OTLKCON_REG_KEY,
		            0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE|KEY_READ, NULL, &hk, NULL);
    if( hk != 0 )
    {
        szBufSize = 4;
        readRetVal = RegQueryValueExW(hk, L"debugLevel", NULL, NULL, (LPBYTE)&dwBuf, &szBufSize);
	    if( readRetVal == ERROR_SUCCESS )
	    {
            debugLevel = (int)dwBuf;
	    }

        szBufSize = OTLKCON_REG_VALUE_MAX_LEN;
        readRetVal = RegQueryValueExW(hk, L"logFile", NULL, NULL, (LPBYTE)szBuf, &szBufSize);
	    if( readRetVal == ERROR_SUCCESS )
	    {
            debugLogFilename = szBuf;
	    }

        szBufSize = 4;
        readRetVal = RegQueryValueExW(hk, L"logToFileEnabled", NULL, NULL, (LPBYTE)&dwBuf, &szBufSize);
	    if( readRetVal == ERROR_SUCCESS )
	    {
            debugFileEnabled = dwBuf?TRUE:FALSE;
	    }

        szBufSize = 4;
        readRetVal = RegQueryValueExW(hk, L"logToMSVCEnabled", NULL, NULL, (LPBYTE)&dwBuf, &szBufSize);
	    if( readRetVal == ERROR_SUCCESS )
	    {
            debugDBEnabled = dwBuf?TRUE:FALSE;
	    }

        szBufSize = 4;
        readRetVal = RegQueryValueExW(hk, L"logToSMEnabled", NULL, NULL, (LPBYTE)&dwBuf, &szBufSize);
	    if( readRetVal == ERROR_SUCCESS )
	    {
            debugSMEnabled = dwBuf?TRUE:FALSE;
	    }
    }

    return result;
}

STDMETHODIMP otlkcon_config::showGui()
{
    HRESULT result       = S_OK;
    PROPSHEETPAGE psp[3] = {0};
    PROPSHEETHEADER psh  = {0};
    HMODULE hMod         = 0;
    
    hMod = GetModuleHandleW(OTLKCON_MSTORE_DLL_NAME);

    // Property Sheet Header
    psh.dwSize      = sizeof(PROPSHEETHEADER);
    psh.dwFlags     = PSH_PROPSHEETPAGE;
    psh.hwndParent  = ulUIParam;
    psh.hInstance   = hMod;
    //  psh.pszIcon =
    //       MAKEINTRESOURCE(IDI_CELL_PROPERTIES);
    // psh.pszCaption    = (LPSTR) "Cell Properties";
    psh.nPages           = 3;//sizeof(psp) / sizeof(PROPSHEETPAGE);
    psh.nStartPage       = 0;
    psh.ppsp             = (LPCPROPSHEETPAGE) &psp;
    psh.pfnCallback      = NULL;//(PFNPROPSHEETCALLBACK)otlkcon_sheetCallback;

    // First Page
    psp[0].dwSize        = sizeof(PROPSHEETPAGE);
    psp[0].dwFlags       = PSP_USECALLBACK; //PSP_USEICONID | PSP_USETITLE;
    //psp[0].hInstance   = NULL;
    psp[0].pszTemplate   = MAKEINTRESOURCE(IDD_GENERALPAGE);
    //psp[0].pszIcon     = MAKEINTRESOURCE(IDI_FONT);
    psp[0].pfnDlgProc    = (DLGPROC)otlkcon_sheet1DlgProc;
    psp[0].lParam        = (LPARAM)this;
    psp[0].pszTitle      = "General Page";
    psp[0].pfnCallback   = otlkcon_sheetCallback;
    psp[0].hInstance     = hMod;

    // Second Page
    psp[1].dwSize        = sizeof(PROPSHEETPAGE);
    psp[1].dwFlags       = PSP_USECALLBACK; //PSP_USEICONID | PSP_USETITLE;
    //psp[1].hInstance   = NULL;
    psp[1].pszTemplate   = MAKEINTRESOURCE(IDD_DEBUGPAGE);
    //psp[1].pszIcon     = MAKEINTRESOURCE(IDI_FONT);
    psp[1].pfnDlgProc    = (DLGPROC)otlkcon_sheet2DlgProc;
    psp[1].lParam        = (LPARAM)this;
    psp[1].pszTitle      = "Debug Page";
    psp[1].pfnCallback   = otlkcon_sheetCallback;
    psp[1].hInstance     = hMod;

    // Third Page
    psp[2].dwSize        = sizeof(PROPSHEETPAGE);
    psp[2].dwFlags       = PSP_USECALLBACK; //PSP_USEICONID | PSP_USETITLE;
    //psp[2].hInstance   = NULL;
    psp[2].pszTemplate   = MAKEINTRESOURCE(IDD_ACCOUNTSPAGE);
    //psp[2].pszIcon     = MAKEINTRESOURCE(IDI_FONT);
    psp[2].pfnDlgProc    = (DLGPROC)otlkcon_sheet3DlgProc;
    psp[2].lParam        = (LPARAM)this;
    psp[2].pszTitle      = "Accounts";
    psp[2].pfnCallback   = otlkcon_sheetCallback;
    psp[2].hInstance     = hMod;

    // Show the sheets
    result = readRegistry();

    INT_PTR ret = PropertySheet(&psh);
    if( isDirty )
    {
        result = writeRegistry();
    }

    return result;
}

HRESULT otlkcon_gui_OnCancel(HWND hwnd )
{
    HRESULT result = S_OK;

    otlkcon_config *conf 
        = (otlkcon_config *)GetWindowLong(hwnd, GWL_USERDATA);

    conf->isDirty = FALSE;

    return result;
}

INT_PTR CALLBACK otlkcon_sheet1DlgProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam )
{
    INT_PTR result = 0;
    HRESULT res = S_OK;
    LPPROPSHEETPAGE sheet;
    otlkcon_config *conf = NULL;
    wchar_t *tmpFilename = NULL;
    bool tmpXPEnable = FALSE;
    bool tmpABEnable = FALSE;

    sheet = (LPPROPSHEETPAGE)lparam;

    switch (uMsg)
    { 
    	case WM_INITDIALOG:
            if( sheet )
            {
                conf = (otlkcon_config *)sheet->lParam;
                tmpFilename = _wcsdup( conf->dbFilename.c_str() );
                tmpXPEnable   = conf->xpEnabled;
                tmpABEnable   = conf->abEnabled;
            }
            
            SetWindowLong(hwnd, GWL_USERDATA, (LONG)conf);

            // PR_PST_PATH
            if( tmpFilename 
                    && (SetDlgItemTextW(hwnd, IDC_DATAFILE_EDIT, tmpFilename) == 0) )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            // PR_OTLKCON_XP_ENABLED
            if( CheckDlgButton(hwnd, IDC_ENABLE_XPP_CHECK, 
                                tmpXPEnable?BST_CHECKED:BST_UNCHECKED) == 0 )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            // PR_OTLKCON_AB_ENABLED
            if( CheckDlgButton(hwnd, IDC_ENABLE_ABP_CHECK, 
                                tmpABEnable?BST_CHECKED:BST_UNCHECKED) == 0 )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            return TRUE;

        case WM_NOTIFY:
            switch (((NMHDR*)lparam)->code)
            {
                case PSN_APPLY:
                    conf = (otlkcon_config *)GetWindowLong(hwnd, GWL_USERDATA);
                    tmpFilename = (wchar_t *)calloc(1, (MAX_PATH+1)*sizeof(wchar_t));
                    if( tmpFilename == NULL )
                    {
                        // We didn't get the memory
                        OTLKCON_DEBUGBREAK;
                        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  
                            OTLKCON_LOG_TARGET_ALL, 
                            L"otlkcon_sheet1DlgProc(): calloc() failed" );

                        return FALSE;
                    }

                     // PR_PST_PATH
                    if( GetDlgItemTextW(hwnd, IDC_DATAFILE_EDIT, tmpFilename, MAX_PATH) 
                                                == 0 )
                    {
                        OTLKCON_LOG_PRINT_LAST_ERROR();
                    }

                    if( wcscmp( conf->dbFilename.c_str(), tmpFilename ) != 0 )
                    {
                        conf->isDirty = TRUE;
                    }
                    conf->dbFilename = tmpFilename;

                    // PR_OTLKCON_XP_ENABLED
                    if( IsDlgButtonChecked(hwnd, IDC_ENABLE_XPP_CHECK ) 
                                                            == BST_CHECKED )
                    {
                        if( conf->xpEnabled == FALSE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->xpEnabled = TRUE;
                    }
                    else
                    {
                        if( conf->xpEnabled == TRUE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->xpEnabled = FALSE;
                    }
                 
                    // PR_OTLKCON_AB_ENABLED
                    if( IsDlgButtonChecked(hwnd, IDC_ENABLE_ABP_CHECK ) 
                                                            == BST_CHECKED )
                    {
                        if( conf->abEnabled == FALSE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->abEnabled = TRUE;
                    }
                    else
                    {
                        if( conf->abEnabled == TRUE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->abEnabled = FALSE;
                    }
                    return FALSE;

                case PSN_QUERYCANCEL:
                    otlkcon_gui_OnCancel( hwnd );
                    return FALSE;
            }
            return FALSE;

        case WM_COMMAND:
            conf = (otlkcon_config *)GetWindowLong(hwnd, GWL_USERDATA);
            switch (LOWORD(wparam))
            {
                case IDC_DATAFILE_BROWSE_BUTTON:
                    switch(HIWORD(wparam))
                    {
                        case BN_CLICKED:
                            {
                            tmpFilename 
                                = (wchar_t *)calloc(1, (MAX_PATH+1)*sizeof(wchar_t));
                            if( GetDlgItemTextW(hwnd, IDC_DATAFILE_EDIT, 
                                tmpFilename, MAX_PATH) 
                                                        == 0 )
                            {
                                OTLKCON_LOG_PRINT_LAST_ERROR();
                            }

                            OPENFILENAMEW openFileName = {0};

                            openFileName.lStructSize = sizeof (OPENFILENAMEW);
                            openFileName.hwndOwner = conf->ulUIParam;

                            openFileName.hInstance 
                                = GetModuleHandleW(OTLKCON_MSTORE_DLL_NAME);;
                            openFileName.Flags = OFN_CREATEPROMPT
                                |OFN_LONGNAMES|OFN_NOREADONLYRETURN;
                            openFileName.lpstrDefExt = OTLKCON_DEFAULT_FILE_EXT;
                            openFileName.lpstrFileTitle 
                                = L"Please Select a New or Existing Database File";
                            openFileName.lpstrFilter 
                                = L"Open Connector DataBase File ( *.OCDB )\0*.ocdb\0\0";
                            openFileName.lpstrFile = tmpFilename;
                            openFileName.nMaxFile  = (MAX_PATH / sizeof(wchar_t)) - 1;

                            BOOL bRes = GetSaveFileNameW( &openFileName );
                            if( bRes == 0 )
                            {
                                // Error or cancel
                                DWORD comRes = CommDlgExtendedError();
                                return TRUE;
                            }

                            // Show the file in the edit box
                            if( tmpFilename && 
                                (SetDlgItemTextW(hwnd, IDC_DATAFILE_EDIT, 
                                            tmpFilename) == 0) )
                            {
                                OTLKCON_LOG_PRINT_LAST_ERROR();
                            }

                            return TRUE;
                            }
                    }
                    return TRUE;
            }

            return TRUE;

        default:
            return DefWindowProc (hwnd, uMsg, wparam, lparam);
    }

    return TRUE;
}

INT_PTR CALLBACK otlkcon_sheet2DlgProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam )
{
    INT_PTR result = 0;
    HRESULT res = S_OK;
    otlkcon_config *conf = NULL;
    LPPROPSHEETPAGE sheet;
    wchar_t *tmpFilename;
    wchar_t  tmpDebugLevel[32] = {0};
    int tmpDebugLevelInt;

    sheet = (LPPROPSHEETPAGE)lparam;

    switch (uMsg)
    { 
    	case WM_INITDIALOG:
            if( sheet )
            {
                conf = (otlkcon_config *)sheet->lParam;
                tmpFilename = _wcsdup( conf->debugLogFilename.c_str() );
                swprintf_s(tmpDebugLevel, 32, L"%d", conf->debugLevel );
            }
            
            SetWindowLong(hwnd, GWL_USERDATA, (LONG)conf);

            SendDlgItemMessage(hwnd, IDC_DEBUG_LEVEL_SPIN, UDM_SETRANGE, 0,
                     MAKELPARAM(-1, 255));

            if( CheckDlgButton(hwnd, IDC_LOG_TO_FILE_CHECK, 
                                conf->debugFileEnabled?BST_CHECKED:BST_UNCHECKED) == 0 )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            if( CheckDlgButton(hwnd, IDC_LOG_TO_MEM_CHECK, 
                                conf->debugSMEnabled?BST_CHECKED:BST_UNCHECKED) == 0 )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            if( CheckDlgButton(hwnd, IDC_LOG_TO_DEBUGGER_CHECK, 
                                conf->debugDBEnabled?BST_CHECKED:BST_UNCHECKED) == 0 )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            if( wcslen(tmpDebugLevel) 
                && (SetDlgItemTextW(hwnd, IDC_DEBUG_LEVEL_EDIT, tmpDebugLevel) == 0) ) 
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }

            if( wcslen(tmpFilename) 
                && (SetDlgItemTextW(hwnd, IDC_LOGFILE_EDIT, tmpFilename) == 0) )
            {
                OTLKCON_LOG_PRINT_LAST_ERROR();
            }
            return TRUE;

        case WM_NOTIFY:
            switch (((NMHDR*)lparam)->code)
            {
                case PSN_APPLY:
                    conf = (otlkcon_config *)GetWindowLong(hwnd, GWL_USERDATA);
                    tmpFilename = (wchar_t *)calloc(1, (MAX_PATH+1)*sizeof(wchar_t));

                    tmpFilename = (wchar_t *)calloc(1, (MAX_PATH+1)*sizeof(wchar_t));

                    if( GetDlgItemTextW(hwnd, IDC_LOGFILE_EDIT, tmpFilename, MAX_PATH) 
                                                == 0 )
                    {
                        OTLKCON_LOG_PRINT_LAST_ERROR();
                    }

                    if( wcscmp( conf->debugLogFilename.c_str(), tmpFilename ) != 0 )
                    {
                        conf->isDirty = TRUE;
                    }
                    conf->debugLogFilename = tmpFilename;

                    if( GetDlgItemTextW(hwnd, IDC_DEBUG_LEVEL_EDIT, tmpFilename, MAX_PATH) 
                                                == 0 )
                    {
                        OTLKCON_LOG_PRINT_LAST_ERROR();
                    }

                    tmpDebugLevelInt = _wtol( tmpFilename );
                    if( tmpDebugLevelInt != conf->debugLevel )
                    {
                        conf->isDirty = TRUE;
                    }
                    conf->debugLevel = tmpDebugLevelInt;

                    if( IsDlgButtonChecked(hwnd, IDC_LOG_TO_FILE_CHECK ) 
                                                            == BST_CHECKED )
                    {
                        if( conf->debugFileEnabled == FALSE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->debugFileEnabled = TRUE;
                    }
                    else
                    {
                        if( conf->debugFileEnabled == TRUE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->debugFileEnabled = FALSE;
                    }

                    if( IsDlgButtonChecked(hwnd, IDC_LOG_TO_MEM_CHECK ) 
                                                            == BST_CHECKED )
                    {
                        if( conf->debugSMEnabled == FALSE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->debugSMEnabled = TRUE;
                    }
                    else
                    {
                        if( conf->debugSMEnabled == TRUE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->debugSMEnabled = FALSE;
                    }

                    if( IsDlgButtonChecked(hwnd, IDC_LOG_TO_DEBUGGER_CHECK ) 
                                                            == BST_CHECKED )
                    {
                        if( conf->debugDBEnabled == FALSE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->debugDBEnabled = TRUE;
                    }
                    else
                    {
                        if( conf->debugDBEnabled == TRUE )
                        {
                            conf->isDirty = TRUE;
                        }
                        conf->debugDBEnabled = FALSE;
                    }
                    return FALSE;

                case PSN_QUERYCANCEL:
                    otlkcon_gui_OnCancel( hwnd );
                    return FALSE;
            }
            return FALSE;

        default: 
            return DefWindowProc (hwnd, uMsg, wparam, lparam);
    }

    return TRUE;
}

HRESULT loadAccountDetails( HWND hwnd, otlkcon_account_details *acct, otlkcon_config *conf )
{
    HRESULT result = S_OK;
    const wchar_t *acctTypeName;
    int index;
    
    acctTypeName = conf->accTypeList[ acct->type ].c_str();
    index = SendDlgItemMessageW( hwnd, IDC_ACCOUNT_TYPE_COMBO, CB_FINDSTRINGEXACT, 
                    (WPARAM)-1, (LPARAM)acctTypeName );
    if( index == CB_ERR )
    {
        index = 0;
    }
    SendDlgItemMessageW(hwnd, IDC_ACCOUNT_TYPE_COMBO, CB_SETCURSEL, index, 0);
    
    SetDlgItemTextW(hwnd, IDC_ACCOUNT_NAME_EDIT,     acct->name.c_str() );
    SetDlgItemTextW(hwnd, IDC_ACCOUNT_USERNAME_EDIT, acct->user.c_str() );
    SetDlgItemTextW(hwnd, IDC_ACCOUNT_PASSWORD_EDIT, acct->pass.c_str() );
    SetDlgItemTextW(hwnd, IDC_ACCOUNT_URI_EDIT,      acct->uri.c_str() );
    SetDlgItemTextW(hwnd, IDC_ACCOUNT_PRINCIPLE_URI_EDIT, 
                                                     acct->principleUri.c_str() );

    CheckDlgButton(hwnd, IDC_ACCOUNT_DEFAULT_CHECK, 
                        acct->defaultAccount?BST_CHECKED:BST_UNCHECKED);

    CheckDlgButton(hwnd, IDC_ACCOUNT_ENABLE_CHECK, 
                        acct->enabled?BST_CHECKED:BST_UNCHECKED);

    CheckDlgButton(hwnd, IDC_ACCOUNT_ENABLE_AB_CHECK, 
                        acct->abEnabled?BST_CHECKED:BST_UNCHECKED);

    return result;
}

INT_PTR CALLBACK otlkcon_sheet3DlgProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam )
{
    INT_PTR result = 0;
    HRESULT res = S_OK;
    otlkcon_config *conf = NULL;
    LPPROPSHEETPAGE sheet;
    HWND tmpHwnd;
    wchar_t *currAccId;
    otlkcon_account_details *tempAcc;
    vector<otlkcon_account_details *>::iterator accI;
    int index;
    wchar_t *strBuff = NULL;

    sheet = (LPPROPSHEETPAGE)lparam;

    switch (uMsg)
    { 
    	case WM_INITDIALOG:
            if( sheet )
            {
                conf = (otlkcon_config *)sheet->lParam;
            }
            
            // Insert an empty account if there aren't any.
            if( conf->accounts.size() < 1 )
            {
                conf->accounts.push_back( new otlkcon_account_details() );
            }

            // Load account details to GUI
            tmpHwnd = GetDlgItem( hwnd, IDC_ACCOUNT_COMBO );
            SendMessage(tmpHwnd, CB_RESETCONTENT, 0, 0); 
            for( vector<otlkcon_account_details *>::iterator i = conf->accounts.begin();
                i != conf->accounts.end(); ++i)
            {
                SendMessageW( tmpHwnd, CB_ADDSTRING, 0, (LPARAM)(*i)->id.c_str() );
            }
            SendMessageW(tmpHwnd, CB_SETCURSEL, 0, 0);
            
            tmpHwnd = GetDlgItem( hwnd, IDC_ACCOUNT_TYPE_COMBO );
            SendMessage(tmpHwnd, CB_RESETCONTENT, 0, 0); 
            for( map<int,wstring>::iterator i = conf->accTypeList.begin(); 
                                                i!=conf->accTypeList.end(); ++i )
            {
                SendMessageW( tmpHwnd, CB_ADDSTRING, 0, (LPARAM)i->second.c_str() );
            }
            
            loadAccountDetails(hwnd, conf->accounts[0], conf );
            SetWindowLong(hwnd, GWL_USERDATA, (LONG)conf);

            return TRUE;

        case WM_COMMAND:
            conf = (otlkcon_config *)GetWindowLong(hwnd, GWL_USERDATA);
            switch (LOWORD(wparam))
            {
                case IDC_ACCOUNT_COMBO:
                    switch(HIWORD(wparam))
                    {
                        case CBN_SELCHANGE:
                            currAccId = (wchar_t *)conf->memObj->pMalloc( OTLKCON_ACCOUNT_STRING_MAX+1 );

                            conf->lastAccountComboIndex
                                = SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, 
                                CB_GETCURSEL, 0, 0);

                            if( conf->lastAccountComboIndex
                                            >= conf->accounts.size() )
                            {
                                conf->lastAccountComboIndex = 0;
                                OTLKCON_DEBUGBREAK;
                            }

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            loadAccountDetails(hwnd, tempAcc, conf );

                            return TRUE;

                        case CBN_KILLFOCUS:
                            currAccId = (wchar_t *)conf->memObj->pMalloc( 
                                (OTLKCON_ACCOUNT_STRING_MAX+1) * sizeof(wchar_t) );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, 
                                WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, (LPARAM)currAccId);

                            if( wcslen(currAccId) < 1 )
                            {
                                MessageBoxW(hwnd, L"Accounts must have an ID",
                                    L"Please name this account", MB_ICONERROR|MB_OK );
                                SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, CB_SETCURSEL,
                                                conf->lastAccountComboIndex, 0);
                                SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, WM_SETFOCUS,
                                                0, 0);
                                return TRUE;
                            }

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( wcscmp(currAccId, tempAcc->id.c_str()) )
                            {
                                // FIXME:  Check that the ID has not been used
                                //         very recently. Ie. is a key in
                                //         accountIdChanges map.
                                map<wstring,wstring>::iterator l 
                                    = conf->accountIdChanges.find( currAccId );
                                if( l == conf->accountIdChanges.end() )
                                {
                                    // Store this relationship for later
                                    conf->accountIdChanges[ tempAcc->id ] = currAccId;

                                    tempAcc->id = currAccId;
                                    SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, 
                                            CB_DELETESTRING, conf->lastAccountComboIndex, 0 );

                                    SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, 
                                            CB_INSERTSTRING, conf->lastAccountComboIndex, 
                                            (LPARAM)currAccId );

                                    conf->isDirty = TRUE;
                                }
                                else
                                {
                                    // This id has already been changed
                                    MessageBoxW(hwnd, L"Id already used",
                                        L"Please do not reuse IDs", MB_ICONERROR|MB_OK);

                                    return TRUE;
                                }     
                            }
                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_TYPE_COMBO:
                    switch(HIWORD(wparam))
                    {
                        case CBN_SELCHANGE:
                            tempAcc = conf->accounts[conf->lastAccountComboIndex];

                            strBuff 
                                = (wchar_t *)conf->memObj->pMalloc( 
                                                        OTLKCON_ACCOUNT_STRING_MAX+1 );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_TYPE_COMBO, 
                                        WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, 
                                                                        (LPARAM)strBuff);

                            tempAcc->type = OTLKCON_ACCOUNT_TYPE_UNDEFINED;
                            for(map<int,wstring>::iterator i = conf->accTypeList.begin();
                                i!=conf->accTypeList.end(); ++i )
                            {
                                if( i->second.compare(strBuff) == 0 )
                                {
                                    tempAcc->type = i->first;
                                    conf->isDirty = TRUE;
                                    break;
                                }
                            }
                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_NAME_EDIT:
                    switch(HIWORD(wparam))
                    {
                        case EN_KILLFOCUS:
                            strBuff 
                                = (wchar_t *)conf->memObj->pMalloc( 
                                                        OTLKCON_ACCOUNT_STRING_MAX+1 );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_NAME_EDIT, 
                                WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, 
                                (LPARAM)strBuff);

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( wcscmp(strBuff, tempAcc->name.c_str()) )
                            {
                                tempAcc->name = strBuff;
                                conf->isDirty = TRUE;
                            }

                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_USERNAME_EDIT:
                    switch(HIWORD(wparam))
                    {
                        case EN_KILLFOCUS:
                            strBuff = (wchar_t *)conf->memObj->pMalloc( OTLKCON_ACCOUNT_STRING_MAX+1 );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_USERNAME_EDIT, 
                                WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, (LPARAM)strBuff);

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( wcscmp(strBuff, tempAcc->user.c_str()) )
                            {
                                tempAcc->user = strBuff;
                                conf->isDirty = TRUE;
                            }

                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_PASSWORD_EDIT:
                    switch(HIWORD(wparam))
                    {
                        case EN_KILLFOCUS:
                            strBuff = (wchar_t *)conf->memObj->pMalloc( OTLKCON_ACCOUNT_STRING_MAX+1 );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_PASSWORD_EDIT, 
                                WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, (LPARAM)strBuff);

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( wcscmp(strBuff, tempAcc->pass.c_str()) )
                            {
                                tempAcc->pass = strBuff;
                                conf->isDirty = TRUE;
                            }

                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_URI_EDIT:
                    switch(HIWORD(wparam))
                    {
                        case EN_KILLFOCUS:
                            strBuff = (wchar_t *)conf->memObj->pMalloc( OTLKCON_ACCOUNT_STRING_MAX+1 );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_URI_EDIT, 
                                WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, (LPARAM)strBuff);

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( wcscmp(strBuff, tempAcc->uri.c_str()) )
                            {
                                tempAcc->uri = strBuff;
                                conf->isDirty = TRUE;
                            }

                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_PRINCIPLE_URI_EDIT:
                    switch(HIWORD(wparam))
                    {
                        case EN_KILLFOCUS:
                            strBuff = (wchar_t *)conf->memObj->pMalloc( OTLKCON_ACCOUNT_STRING_MAX+1 );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_PRINCIPLE_URI_EDIT, 
                                WM_GETTEXT, OTLKCON_ACCOUNT_STRING_MAX, (LPARAM)strBuff);

                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( wcscmp(strBuff, tempAcc->principleUri.c_str()) )
                            {
                                tempAcc->principleUri = strBuff;
                                conf->isDirty = TRUE;
                            }

                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_ENABLE_AB_CHECK:
                    switch(HIWORD(wparam))
                    {
                        case BN_CLICKED:
                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( IsDlgButtonChecked(hwnd, IDC_ACCOUNT_ENABLE_AB_CHECK ) 
                                                            == BST_CHECKED )
                            {
                                if( tempAcc->abEnabled==FALSE )
                                {
                                    conf->isDirty = TRUE;
                                    tempAcc->abEnabled = TRUE;
                                }    
                            }
                            else
                            {
                                if( tempAcc->abEnabled==TRUE )
                                {
                                    conf->isDirty = TRUE;
                                    tempAcc->abEnabled = FALSE;
                                }   
                            }
                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_DEFAULT_CHECK:
                    switch(HIWORD(wparam))
                    {
                        case BN_CLICKED:
                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( IsDlgButtonChecked(hwnd, IDC_ACCOUNT_DEFAULT_CHECK ) 
                                                            == BST_CHECKED )
                            {
                                if( tempAcc->defaultAccount==FALSE )
                                {
                                    conf->isDirty = TRUE;
                                    tempAcc->defaultAccount = TRUE;
                                }    
                            }
                            else
                            {
                                if( tempAcc->defaultAccount==TRUE )
                                {
                                    conf->isDirty = TRUE;
                                    tempAcc->defaultAccount = FALSE;
                                }   
                            }
                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_ENABLE_CHECK:
                    switch(HIWORD(wparam))
                    {
                        case BN_CLICKED:
                            tempAcc = conf->accounts[conf->lastAccountComboIndex];
                            if( IsDlgButtonChecked(hwnd, IDC_ACCOUNT_ENABLE_CHECK ) 
                                                            == BST_CHECKED )
                            {
                                if( tempAcc->enabled==FALSE )
                                {
                                    conf->isDirty = TRUE;
                                    tempAcc->enabled = TRUE;
                                }    
                            }
                            else
                            {
                                if( tempAcc->enabled==TRUE )
                                {
                                    conf->isDirty = TRUE;
                                    tempAcc->enabled = FALSE;
                                }   
                            }
                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_NEW_BUTTON:
                    switch(HIWORD(wparam))
                    {
                        case BN_CLICKED:
                            if( conf->accounts.size() >= OTLKCON_ACCOUNT_MAX )
                            {
                                MessageBoxW(hwnd, L"Maximum number of accounts reached",
                                    L"Too many accounts", MB_ICONERROR|MB_OK);

                                return TRUE;
                            }

                            tempAcc = new otlkcon_account_details();
                            strBuff = (wchar_t *)conf->memObj->pMalloc( 32 );
                            for(int j=1; j<OTLKCON_ACCOUNT_MAX+2; j++)
                            {
                                tempAcc->id = OTLKCON_ACCOUNT_DEFAULT_ID;
                                _itow_s(j, strBuff, 32, 10 );
                                tempAcc->id += strBuff;
                                index = SendDlgItemMessageW( hwnd, IDC_ACCOUNT_COMBO, 
                                                CB_FINDSTRINGEXACT, (WPARAM)-1, 
                                                (LPARAM)tempAcc->id.c_str() );
                                if( index == CB_ERR )
                                {
                                    break;
                                }
                            }
                            conf->accounts.push_back( tempAcc );

                            conf->lastAccountComboIndex = conf->accounts.size()-1;

                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, CB_ADDSTRING,
                                                0, (LPARAM)tempAcc->id.c_str() );
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, CB_SETCURSEL,
                                                conf->lastAccountComboIndex, 0);
                            loadAccountDetails(hwnd, tempAcc, conf);

                            conf->isDirty = TRUE;

                            return TRUE;
                    }
                    return TRUE;

                case IDC_ACCOUNT_DEL_BUTTON:
                    switch(HIWORD(wparam))
                    {
                        case BN_CLICKED:
                            if( conf->accounts.size() < 2 )
                            {
                                MessageBoxW(hwnd, L"Can not delete the only account",
                                    L"Can not delete account", MB_ICONERROR|MB_OK);

                                return TRUE;
                            }

                            index = SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, CB_GETCURSEL,
                                                0, 0);
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, CB_DELETESTRING,
                                                index, 0 );
                            if( conf->accounts.size() > index )
                            {
                                conf->accounts.erase( conf->accounts.begin()+index );
                            }
                            else
                            {
                                OTLKCON_DEBUGBREAK;
                            }
                            index = (index-1<0)?0:index-1;
                            SendDlgItemMessageW(hwnd, IDC_ACCOUNT_COMBO, CB_SETCURSEL,
                                index, 0);
                            conf->lastAccountComboIndex = index;
                            loadAccountDetails(hwnd, conf->accounts[index], conf);

                            conf->isDirty = TRUE;
                            return TRUE;                  
                    }
                    return TRUE;
            }
            return TRUE;

        case WM_NOTIFY:
            switch (((NMHDR*)lparam)->code)
            {
                case PSN_APPLY:
                    ;
                    return FALSE;

                case PSN_QUERYCANCEL:
                    otlkcon_gui_OnCancel( hwnd );
                    return FALSE;
            }
            return FALSE;

        default:
            return DefWindowProc (hwnd, uMsg, wparam, lparam);
    }

    return TRUE;
}

INT_PTR CALLBACK otlkcon_sheet3bDlgProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam )
{
    switch (uMsg)
    { 
        default:
            return DefWindowProc (hwnd, uMsg, wparam, lparam);
    }

    return TRUE;
}

UINT CALLBACK otlkcon_sheetCallback( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp )
{
    UINT result = 0;
    HRESULT res = S_OK;
    otlkcon_config *conf = NULL;

    if( ppsp )
    {
        conf = (otlkcon_config *)ppsp->lParam;
    }

    switch( uMsg )
    {
        case PSPCB_RELEASE:
            
            break;
    }

    return TRUE;
}
